package br.fatec.util;

import java.util.HashMap;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.NoResultException;
import javax.persistence.Persistence;
import javax.persistence.Query;

import org.hibernate.Session;

public class Persistencia {

	private EntityManagerFactory factory;
	private EntityManager manager;

	public Persistencia() {
		this.factory = Persistence.createEntityManagerFactory("flamel");
		this.open();
	}

	public void open() {
		this.manager = factory.createEntityManager();
	}

	private void close() {

		if (this.manager.isOpen()) {
			this.manager.clear();
			this.manager.close();
		}
	}

	public static boolean verificarConexao() {
		EntityManagerFactory factory;
		EntityManager manager;

		try {
			factory = Persistence.createEntityManagerFactory("flamel");
			manager = factory.createEntityManager();

			Session hibernateSession = (Session) manager.getDelegate();

			if (hibernateSession.isConnected() && hibernateSession.isOpen()) {
				hibernateSession.disconnect();
			}

			return true;
		} catch (Exception e) {
			Log.gravarLog(e);
			return false;
		}
	}

	public void refresh(Object obj) throws Exception {
		try {
			open();
			this.manager.getTransaction().begin();
			this.manager.refresh(obj);
			this.manager.getTransaction().commit();
		} finally {
			if (factory != null && manager != null)
				close();
		}
	}

	public void cadastrar(Object obj) throws Exception {
		try {
			open();
			this.manager.getTransaction().begin();
			this.manager.persist(obj);
			this.manager.getTransaction().commit();

			this.manager.getTransaction().begin();
			this.manager.refresh(obj);
			this.manager.getTransaction().commit();
		} finally {
			if (factory != null && manager != null)
				close();
		}
	}
	
	public void alterar(Object obj) throws Exception {
		try {
			open();
			this.manager.getTransaction().begin();
			obj = this.manager.merge(obj);
			this.manager.getTransaction().commit();
		} finally {
			if (factory != null && manager != null)
				close();
		}
	}

	public void excluir(Class<?> classe, Object codigo) throws Exception {
		try {
			open();
			this.manager.getTransaction().begin();
			this.manager.remove(manager.getReference(classe, codigo));
			this.manager.getTransaction().commit();
		} finally {
			if (factory != null && manager != null)
				close();
		}
	}
	
	public Object cconsultar(Class<?> classe, Object codigo) throws Exception {
		try {
			open();
			this.manager.getTransaction().begin();
			Object requisicao = this.manager.find(classe, codigo);
			this.manager.getTransaction().commit();

			return requisicao;
		} catch (NoResultException ex) {
			return null;
		} finally {
			if (factory != null && manager != null)
				close();
		}
	}

	public Object consultar(Class<?> classe, String strQuery, HashMap<String, Object> parametros) throws Exception {
		try {
			open();
			this.manager.getTransaction().begin();
			Query query = this.manager.createNativeQuery(strQuery, classe);
			for(String key : parametros.keySet())
				query.setParameter(key, parametros.get(key));
			Object requisicao = query.getSingleResult();
			this.manager.getTransaction().commit();

			return requisicao;
		} catch (NoResultException ex) {
			return null;
		} finally {
			if (factory != null && manager != null)
				close();
		}
	}
	
	public List<?> listar(Class<?> classe, String strQuery, HashMap<String, Object> parametros) throws Exception {
		try {
			open();
			this.manager.getTransaction().begin();
			Query query = this.manager.createNativeQuery(strQuery, classe);
			for(String key : parametros.keySet())
				query.setParameter(key, parametros.get(key));
			List<?> lstObjetos = query.getResultList();
			this.manager.getTransaction().commit();
			return lstObjetos;
		} catch (NoResultException ex) {
			return null;
		} finally {
			if (factory != null && manager != null)
				close();
		}
	}
}
